package zzg.study.reactor;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.*;

/**
 * @Classname Acceptor
 * @Description TODO
 * @Date 2025/1/27 16:17
 * @Author zhuzhenguo
 */
public class Acceptor extends ServiceThread {

    private final Server server;

    private final ServerSocketChannel serverSocketChannel;

    private final Collection<PollerIO> ioThreads;

    private Iterator<PollerIO> ioThreadIterator;

    public Acceptor(String name, Server server, Set<PollerIO> ioThreads) throws IOException {
        super(name);
        this.server = server;
        this.serverSocketChannel = ServerSocketChannel.open();
        this.serverSocketChannel.configureBlocking(false);
        this.serverSocketChannel.socket().bind(new java.net.InetSocketAddress(server.getPort()));
        // 注册到selector上
        this.serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
        this.ioThreads = Collections.unmodifiableList(new ArrayList<>(ioThreads));
        this.ioThreadIterator = this.ioThreads.iterator();
    }

    @Override
    public void run() {
        while (!server.stopped && !serverSocketChannel.socket().isClosed()) {
            try {
                this.selector.select();
                Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    if (!key.isValid()) {
                        continue;
                    }
                    if (key.isAcceptable()) {
                        doAccept(key);
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void doAccept(SelectionKey key) throws IOException {
        SocketChannel socketChannel = this.serverSocketChannel.accept();
        socketChannel.configureBlocking(false);
        if (ioThreadIterator.hasNext()) {
            this.ioThreadIterator = this.ioThreads.iterator();
        }
        PollerIO pollerIO = ioThreadIterator.next();
        pollerIO.addAcceptedChannel(socketChannel);
    }
}

